package com.shxzz.easy12306.framework.starter.designpattern.strategy;

import com.shxzz.easy12306.framework.starter.base.ApplicationContextHolder;
import com.shxzz.easy12306.framework.starter.base.init.ApplicationInitializingEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;

/**
 * 策略选择器
 *
 * @author shxzz
 * @create 2024-02-20-21:34
 */
@Slf4j
public class AbstractStrategyChoose {
    private final Map<String, AbstractExecuteStrategy> executeStrategyContext = new HashMap<>();

    /**
     * 精准匹配策略并执行
     * @param mark 策略标识
     * @param requestParam 请求参数
     */
    public <REQUEST> void chooseAndExecute(String mark, REQUEST requestParam) {
        chooseAndExecute(mark, requestParam, false);
    }

    /**
     * 匹配策略并执行
     * @param mark 策略标识
     * @param requestParam 请求参数
     * @param isPatternMatch 泛匹配标志
     */
    public <REQUEST> void chooseAndExecute(String mark, REQUEST requestParam, boolean isPatternMatch) {
        AbstractExecuteStrategy executeStrategy = choose(mark, isPatternMatch);
        executeStrategy.execute(requestParam);
    }

    /**
     * 精准匹配策略并执行，带返回结果
     * @param mark 策略标识
     * @param requestParam 请求参数
     */
    public <REQUEST, RESPONSE> RESPONSE chooseAndExecuteResp(String mark, REQUEST requestParam) {
        return chooseAndExecuteResp(mark, requestParam, false);
    }

    /**
     * 匹配策略并执行，带返回结果
     * @param mark 策略标识
     * @param requestParam 请求参数
     * @param isPatternMatch 泛匹配标志
     */
    public <REQUEST, RESPONSE> RESPONSE chooseAndExecuteResp(String mark, REQUEST requestParam, boolean isPatternMatch) {
        AbstractExecuteStrategy executeStrategy = choose(mark, isPatternMatch);
        return (RESPONSE) executeStrategy.executeResp(requestParam);
    }

    public AbstractExecuteStrategy choose(String mark, boolean isPatternMatch) {
        if (!isPatternMatch) {
            return Optional.ofNullable(executeStrategyContext.get(mark))
                    .orElseThrow(() -> new RuntimeException("不存在对应的执行策略，标记为：" + mark));
        }
        return executeStrategyContext.values().stream()
                .filter(executeStrategy -> StringUtils.hasLength(executeStrategy.patternMatchStr()))
                .filter(executeStrategy -> Pattern.compile(executeStrategy.patternMatchStr()).matcher(mark).matches())
                .findFirst()
                .orElseThrow(() -> new RuntimeException("不存在对应的执行策略，标记为：" + mark));
    }

    @EventListener(ApplicationInitializingEvent.class)
    public void initExecuteStrategyContext() {
        Map<String, AbstractExecuteStrategy> strategyMap = ApplicationContextHolder.getBeansOfType(AbstractExecuteStrategy.class);
        strategyMap.values().forEach(executeStrategy -> {
            if (executeStrategyContext.containsKey(executeStrategy.mark())) {
                log.error("存在相同标记的执行策略，标记为：{}", executeStrategy.mark());
                throw new RuntimeException("存在相同标记的执行策略，标记为：" + executeStrategy.mark());
            }
            executeStrategyContext.put(executeStrategy.mark(), executeStrategy);
        });
    }

}
